﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;
using Lm.Common.ExtensionMethods;

namespace Lm.Common.DAL
{
    public abstract class DALBase : IDAL
    {
        protected System.Data.Common.DbConnection Connection { get; set; }

        public DALBase(System.Data.Common.DbConnection connection)
        {
            this.Connection = connection;
        }

        protected abstract System.Data.Common.DbCommand CreateCommand();

        protected abstract DbDataAdapter CreateAdapter(DbCommand cmd);

        protected int ExecuteNonQuery(string commandText, DbParameter[] parameters)
        {
            try
            {
                System.Data.Common.DbCommand cmd = this.CreateCommand();
                cmd.Connection = this.Connection;
                cmd.CommandText = commandText;
                cmd.Parameters.AddRange(parameters);
                this.Connection.Open();
                return cmd.ExecuteNonQuery();
            }
            finally
            { this.Connection.Close(); }
        }

        protected object ExecuteScalar(string commandText, DbParameter[] parameters)
        {
            try
            {
                System.Data.Common.DbCommand cmd = this.CreateCommand();
                cmd.Connection = this.Connection;
                cmd.CommandText = commandText;
                cmd.Parameters.AddRange(parameters);
                this.Connection.Open();
                return cmd.ExecuteScalar();
            }
            finally
            { this.Connection.Close(); }
        }

        protected System.Data.DataTable QueryDataTable(string commandText, DbParameter[] parameters)
        {
            try
            {
                System.Data.Common.DbCommand cmd = this.CreateCommand();
                cmd.Connection = this.Connection;
                cmd.CommandText = commandText;
                cmd.Parameters.AddRange(parameters);
                var adapter = this.CreateAdapter(cmd);
                var dt = new System.Data.DataTable();
                adapter.Fill(dt);
                return dt;
            }
            finally
            { this.Connection.Close(); }
        }

        //protected void CheckViewModel<T>() where T : IModelBase
        //{
        //    if (typeof(T).GetCustomAttributes(typeof(ViewModelAttribute), true).Length > 0)
        //    {
        //        throw new Exception("只能对视图进行查询");
        //    }
        //}

        public long Insert<T>(System.Linq.Expressions.Expression<Func<T>> fields) where T : Lm.Common.DAL.IModelBase
        {

            //this.CheckViewModel<T>();
            return this.ExecuteInsert<T>(fields);
        }

        protected abstract long ExecuteInsert<T>(System.Linq.Expressions.Expression<Func<T>> fields) where T : IModelBase;

        public bool Insert<T>(T model) where T : IModelBase
        {
            //this.CheckViewModel<T>();
            return this.ExecuteInsert(model);
        }

        protected abstract bool ExecuteInsert<T>(T model) where T : IModelBase;

        public int Delete<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase
        {
            //this.CheckViewModel<T>();
            return this.ExecuteDelete<T>(conditions);
        }

        public abstract int ExecuteDelete<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase;

        public int Update<T>(T model, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase
        {
            //this.CheckViewModel<T>();
            return this.ExecuteUpdate<T>(model, conditions);
        }

        public abstract int ExecuteUpdate<T>(T model, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase;

        public int Update<T>(System.Linq.Expressions.Expression<Func<T, T>> fields, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase
        {
            //this.CheckViewModel<T>();
            return this.ExecuteUpdate<T>(fields, conditions);
        }

        public abstract int ExecuteUpdate<T>(System.Linq.Expressions.Expression<Func<T, T>> fields, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : Lm.Common.DAL.IModelBase;

        public List<T> Select<T>(System.Linq.Expressions.Expression<Func<T>> selectFields, System.Linq.Expressions.Expression<Func<T>> orderByFields, OrderByOption option, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase, new()
        {
            var dt = this.QueryDataTable<T>(selectFields, orderByFields, option, conditions);
            return dt.ToModelList<T>(SchemaNotSame.UseSource);
        }

        public abstract System.Data.DataTable QueryDataTable<T>(System.Linq.Expressions.Expression<Func<T>> selectFields, System.Linq.Expressions.Expression<Func<T>> orderByFields, OrderByOption option, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase;

        public List<T> Select<T>(long pageSize, long pageIndex, out long recordCount, System.Linq.Expressions.Expression<Func<T>> selectFields, System.Linq.Expressions.Expression<Func<T>> orderByFields, OrderByOption option, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase, new()
        {
            var dt = this.QueryDataTable<T>(pageSize, pageIndex, out recordCount, selectFields, orderByFields, option, conditions);
            return dt.ToModelList<T>(SchemaNotSame.UseSource);
        }

        public abstract System.Data.DataTable QueryDataTable<T>(long pageSize, long pageIndex, out long recordCount, System.Linq.Expressions.Expression<Func<T>> selectFields, System.Linq.Expressions.Expression<Func<T>> orderByFields, OrderByOption option, params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase;

        public abstract int Count<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase;

        public bool Exist<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase
        {
            return this.Count<T>(conditions) > 0;
        }

        public bool IsSingle<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase
        {
            return this.Count<T>(conditions) == 1;
        }


        public List<T> Select<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase, new()
        {
            var dt = this.QueryDataTable(null, null, OrderByOption.ASC, conditions);
            return dt.ToModelList<T>(SchemaNotSame.ThrowException);
        }


        public T GetSingle<T>(params System.Linq.Expressions.Expression<Func<T, bool>>[] conditions) where T : IModelBase, new()
        {
            var dt = this.QueryDataTable(null, null, OrderByOption.ASC, conditions);
            return dt.ToModelList<T>(SchemaNotSame.ThrowException).Single();
        }
    }
}